//
//  STSilentLivenessController.m
//  STSilentLivenessController
//
//  Created by huoqiuliang on 16/8/15.
//  Copyright © 2016年 sensetime. All rights reserved.
//

#import "STSilentLivenessController.h"
#import "STSilentLivenessView.h"
#import "STSilentLivenessCommon.h"
#import "STSilentLivenessCamera.h"
#import "UIView+EX.h"
#define WINDOW_FRAME_TO_EDGE 43
#define PAD_WINDOW_FRAME_TO_EDGE (77 * 2)
#define WINDOW_RATIO 400 / 290
#define PAD_WINDOW_RATIO 305 / 230
@interface STSilentLivenessController () <STSilentLivenessDetectorDelegate, STSilentLivenessCameraDelegate> {
    NSMutableArray *_previousSecondTimestamps;
}
@property (nonatomic, strong) STSilentLivenessCamera *silentLivenessCamera;

@property (nonatomic, strong) NSString *bundlePathStr;

@property (nonatomic, weak) id<STSilentLivenessControllerDelegate> controllerDelegate;

@property (nonatomic, weak) id<STSilentLivenessDetectorDelegate> detectorDelegate;

@property (nonatomic, strong) STSilentLivenessView *silentLivenessView;

@property (strong, nonatomic) NSOperationQueue *mainQueue;
@property (nonatomic, assign) CGRect prepareframe;
@property (nonatomic, assign) CGRect previewframe;
@property (nonatomic, assign) BOOL isCameraPermission;
@property (nonatomic, assign) CFAbsoluteTime lastUpdateTime;

@end

@implementation STSilentLivenessController

- (instancetype)init {
    NSLog(@" ╔—————————————————————— WARNING —————————————————————╗");
    NSLog(@" | [[STLivenessController alloc] init] is not allowed |");
    NSLog(@" |     Please use  \"initWithApiKey\" , thanks !    |");
    NSLog(@" ╚————————————————————————————————————————————————————╝");
    [self doesNotRecognizeSelector:_cmd];
    return nil;
}

#pragma - mark -
#pragma - mark Public method

- (instancetype)initWithSetDelegate:(id<STSilentLivenessDetectorDelegate, STSilentLivenessControllerDelegate>)delegate {
    self = [super init];
    if (self) {
        {
            // 资源路径
            _bundlePathStr = [[NSBundle mainBundle] pathForResource:@"st_silent_liveness_resource" ofType:@"bundle"];

            // 获取授权文件路径
            NSString *licensePathStr = [[NSBundle mainBundle] pathForResource:@"SenseID_Liveness_Silent" ofType:@"lic"];

            // 获取模型路径
            NSString *detectionModelPathStr =
                [NSString pathWithComponents:@[self.bundlePathStr, @"model", @"M_Detect_Hunter_SmallFace.model"]];

            NSString *alignmentModelPathStr =
                [NSString pathWithComponents:@[self.bundlePathStr, @"model", @"M_Align_occlusion.model"]];

            NSString *frameSelectorModelPathStr =
                [NSString pathWithComponents:@[self.bundlePathStr, @"model", @"M_Liveness_Cnn_half.model"]];
            NSString *antiSpoofingModelPathStr =
                [NSString pathWithComponents:@[self.bundlePathStr, @"model", @"M_Liveness_Antispoofing.model"]];
            NSString *faceQualityModelPathStr =
                [NSString pathWithComponents:@[self.bundlePathStr, @"model", @"M_Face_Quality.model"]];

            _detector = [[STSilentLivenessDetector alloc] initWithDetectionModelPath:detectionModelPathStr
                                                                  alignmentModelPath:alignmentModelPathStr
                                                              frameSelectorModelPath:frameSelectorModelPathStr
                                                               antiSpoofingModelPath:antiSpoofingModelPathStr
                                                                faceQualityModelPath:faceQualityModelPathStr
                                                                         licensePath:licensePathStr
                                                                         setDelegate:self];
            [self setDetectorConfiguration];
        }

        _previousSecondTimestamps = [[NSMutableArray alloc] init];

        if (IS_IPHONE) {
            _prepareframe = CGRectMake(WINDOW_FRAME_TO_EDGE,
                                       KStatusBarHeight + KNavigationBarHeight + 40,
                                       kSTScreenWidth - WINDOW_FRAME_TO_EDGE * 2,
                                       (kSTScreenWidth - WINDOW_FRAME_TO_EDGE * 2) * WINDOW_RATIO);
        } else {
            _prepareframe = CGRectMake(PAD_WINDOW_FRAME_TO_EDGE,
                                       KStatusBarHeight + KNavigationBarHeight + 68 * 2,
                                       kSTScreenWidth - PAD_WINDOW_FRAME_TO_EDGE * 2,
                                       (kSTScreenWidth - PAD_WINDOW_FRAME_TO_EDGE * 2) * PAD_WINDOW_RATIO);
        }
        _previewframe = CGRectMake(0, 0, kSTScreenWidth, kSTScreenHeight - _prepareframe.origin.y);

        _mainQueue = [NSOperationQueue mainQueue];

        if (_detectorDelegate != delegate) {
            _detectorDelegate = delegate;
            _controllerDelegate = delegate;
        }

        _isCameraPermission = NO;

        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(willResignActive)
                                                     name:UIApplicationWillResignActiveNotification
                                                   object:nil];
    }
    return self;
}


#pragma mark-- Detector 配置项

- (void)setDetectorConfiguration {
    if (_detector != nil) {
        //设置静默活体检测的超时时间
        [_detector setDetectTimeout:kSenseIdSilentLivenessDefaultTimeOutDuration];
        //设置静默活体通过条件
        [_detector setPassConditionMinDuration:0 minFrames:4];
        //设置人脸远近判断条件
        [_detector setFaceDistanceRateWithFarRate:0.4 closeRate:0.8];
        // 设置活体防hack阈值
        [_detector setHackThreshold:kSenseIdSilentLivenessDefaultHackThreshold];
        /* // 需要质检时，解注以下代码
            // 光照检测
            [_detector setIlluminationFilterEnable:YES
                                darkLightThreshold:kSenseIdSilentLivenessDefaultDarkLightThreshold
                              strongLightThreshold:kSenseIdSilentLivenessDefaultStrongLightThreshold];

            // 模糊检测
            [_detector setBlurryFilterEnable:YES threshold:kSenseIdSilentLivenessDefaultBlurThreshold];

            // 闭眼检测
            [_detector setEyeOpenFilterEnable:YES threshold:kSenseIdSilentLivenessDefaultEyeOpenThreshold];
         */
        // 设置是否对活体进行遮挡检测
        [_detector setOcclusionEnable:YES];
    }
}

#pragma - mark Life Cycle

- (void)loadView {
    [super loadView];
    [self setupUI];
}

- (void)viewDidLoad {
    [super viewDidLoad];

    UIBarButtonItem *backItem =
        [[UIBarButtonItem alloc] initWithImage:[[self imageWithFullFileName:@"st_scan_back.png"]
                                                   imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]
                                         style:UIBarButtonItemStylePlain
                                        target:self
                                        action:@selector(onBack)];
    self.navigationItem.leftBarButtonItem = backItem;
    self.navigationItem.title = @"静默活体";

    self.silentLivenessCamera = [[STSilentLivenessCamera alloc] initWithPrepareframe:self.prepareframe
                                                                        previewframe:self.previewframe];
    self.silentLivenessCamera.delegate = self;

    [self.view.layer addSublayer:self.silentLivenessCamera.captureVideoPreviewLayer];
    [self.view bringSubviewToFront:self.silentLivenessView];
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    if (self.detector) {
        [self.silentLivenessCamera startRunning];
    }
}

- (void)dealloc {
    [self.silentLivenessCamera stopRunning];
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

#pragma - mark -
#pragma - mark Private Methods

- (void)willResignActive {
    if (self.controllerDelegate &&
        [self.controllerDelegate respondsToSelector:@selector(silentLivenessControllerDeveiceError:)] &&
        _isCameraPermission) {
        [self.mainQueue addOperationWithBlock:^{
            [self.controllerDelegate silentLivenessControllerDeveiceError:STIDSilentLiveness_WILL_RESIGN_ACTIVE];
        }];
    }
}

- (void)setupUI {
    self.view.backgroundColor = [UIColor blackColor];
    self.silentLivenessView =
        [[STSilentLivenessView alloc] initWithFrame:CGRectMake(0, 0, kSTScreenWidth, kSTScreenHeight)
                                        windowFrame:self.prepareframe];
    [self.view addSubview:self.silentLivenessView];

    [self showPromptButtonText:@"请将人脸置于屏幕中央保持不动" imageName:@"notice.png"];
}

- (UIImage *)imageWithFullFileName:(NSString *)fileName {
    NSString *filePath = [NSString pathWithComponents:@[self.bundlePathStr, @"images", fileName]];

    return [UIImage imageWithContentsOfFile:filePath];
}

#pragma - mark -
#pragma - mark Event Response

- (void)onBack {
    self.isCameraPermission = NO;
    [self.detector stop];
    if (self.controllerDelegate && [self.controllerDelegate respondsToSelector:@selector(cancelDetect)]) {
        [self.mainQueue addOperationWithBlock:^{
            [self.controllerDelegate cancelDetect];
        }];
    }
}

#pragma - mark -
#pragma - mark STSilentLivenessCameraDelegate

- (void)cameraAuthorizationSuccessfully {
    self.isCameraPermission = YES;
    if (self.detector) {
        [self.detector start];
    }
}

- (void)didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
               faceOrientaion:(STIDSilentLivenessFaceOrientaion)faceOrientation
            imagePreparewRect:(CGRect)imagePreparewRect
             imagePreviewRect:(CGRect)imagePreviewRect {
    if (self.detector && self.silentLivenessCamera) {
        [self.detector inputDataWithSampleBuffer:sampleBuffer
                                  faceOrientaion:faceOrientation
                                imagePrepareRect:imagePreparewRect];
    }
}

- (void)cameraAuthorizationFailed {
    if (self.controllerDelegate &&
        [self.controllerDelegate respondsToSelector:@selector(silentLivenessControllerDeveiceError:)]) {
        [self.mainQueue addOperationWithBlock:^{
            [self.controllerDelegate silentLivenessControllerDeveiceError:STIDSilentLiveness_E_CAMERA];
        }];
    }
}

#pragma - mark STSilentLivenessDetectorDelegate


- (void)silentLivenessSuccessWithProtobufData:(NSData *)protobufData
                                       images:(NSArray *)images
                                    faceRects:(NSArray *)faceRects {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    if (self.detectorDelegate &&
        [self.detectorDelegate respondsToSelector:@selector(silentLivenessSuccessWithProtobufData:images:faceRects:)]) {
        [self.mainQueue addOperationWithBlock:^{
            [self.detectorDelegate silentLivenessSuccessWithProtobufData:protobufData
                                                                  images:images
                                                               faceRects:faceRects];
        }];
    }
}

- (void)silentLivenessFailureWithErrorCode:(STIDSilentLivenessResult)livenessResult
                              protobufData:(NSData *)protobufData
                                    images:(NSArray *)images
                                 faceRects:(NSArray *)faceRects {
    //重新开始检测
    //    if (faceError == STIDSilentLiveness_E_HACK) {
    //        [self.detector reStartDetection];
    //        return;
    //    }

    if (self.detectorDelegate &&
        [self.detectorDelegate respondsToSelector:@selector(silentLivenessFailureWithErrorCode:
                                                                                  protobufData:images:faceRects:)]) {
        [self.mainQueue addOperationWithBlock:^{
            [self.detectorDelegate silentLivenessFailureWithErrorCode:livenessResult

                                                         protobufData:protobufData
                                                               images:images
                                                            faceRects:faceRects];
        }];
    }
}

- (void)silentLivenessDidCancel {
//    if (self.detectorDelegate && [self.detectorDelegate respondsToSelector:@selector(silentLivenessDidCancel)]) {
//        [self.mainQueue addOperationWithBlock:^{
//            [self.detectorDelegate silentLivenessDidCancel];
//        }];
//    }
}

- (void)silentLivenessFaceStatusChangedWithFaceDistance:(STIDSilentLivenessFaceDistanceStatus)distanceStatus
                                           facePosition:(STIDSilentLivenessFacePositionStatus)boundStatus
                                            faceQuality:(STIDSilentLivenessQuailityStatus)faceQuality
                                          faceOcclusion:(STSilentLivenessFace *)faceOcclusion {
    CFAbsoluteTime currentTime = CFAbsoluteTimeGetCurrent() * 1000;

    if ((currentTime - self.lastUpdateTime) > 300) {
        /// 文案提示优先级：远近 > 出框 > 强暗光 > 遮挡
        if (distanceStatus == STIDSilentLiveness_FACE_TOO_FAR) {
            [self showPromptButtonText:@"请移动手机靠近面部" imageName:@"far away.png"];
        } else if (distanceStatus == STIDSilentLiveness_FACE_TOO_CLOSE) {
            [self showPromptButtonText:@"请移动手机远离面部" imageName:@"close to.png"];
        } else if (boundStatus != STIDSilentLiveness_POSITION_FACE_NORMAL) {
            [self showPromptButtonText:@"请将人脸置于屏幕中央保持不动" imageName:@"notice.png"];
        } else if (faceQuality == STIDSilentLiveness_QUALITY_LIGHT_DARK) {
            [self showPromptButtonText:@"当前光线过暗，请调整光线" imageName:@"notice.png"];
        } else if (faceQuality == STIDSilentLiveness_QUALITY_LIGHT_STRONG) {
            [self showPromptButtonText:@"当前光线过亮，请调整光线" imageName:@"notice.png"];
        } else if (faceOcclusion.isOcclusion) {
            [self showPromptButtonText:[self faceOcclusionStringWithFaceModel:faceOcclusion] imageName:@"notice.png"];
        } else if (distanceStatus == STIDSilentLiveness_DISTANCE_FACE_NORMAL &&
                   boundStatus == STIDSilentLiveness_POSITION_FACE_NORMAL &&
                   faceQuality == STIDSilentLiveness_QUALITY_NORMAL) {
            [self showPromptButtonText:@"活体检测中" imageName:@"detection.png"];
        } else {
            [self showPromptButtonText:@"请将人脸置于屏幕中央保持不动" imageName:@"notice.png"];
        }

        self.lastUpdateTime = CFAbsoluteTimeGetCurrent() * 1000;
    }
}

- (NSString *)faceOcclusionStringWithFaceModel:(STSilentLivenessFace *)face {
    NSMutableString *tempStr = [[NSMutableString alloc] init];

    if (face.browOcclusionStatus == STIDSilentLiveness_OCCLUSION) {
        [tempStr appendFormat:@"眉毛、"];
    }
    if (face.eyeOcclusionStatus == STIDSilentLiveness_OCCLUSION) {
        [tempStr appendFormat:@"眼部、"];
    }
    if (face.noseOcclusionStatus == STIDSilentLiveness_OCCLUSION) {
        [tempStr appendFormat:@"鼻部、"];
    }
    if (face.mouthOcclusionStatus == STIDSilentLiveness_OCCLUSION) {
        [tempStr appendFormat:@"嘴部"];
    }
    NSString *theLast = [tempStr substringFromIndex:[tempStr length] - 1];
    if ([theLast isEqualToString:@"、"]) {
        tempStr = (NSMutableString *) [tempStr substringToIndex:([tempStr length] - 1)];
    }
    return [NSString stringWithFormat:@"请正对手机，去除%@遮挡", tempStr];
}

- (void)showPromptButtonText:(NSString *)text imageName:(NSString *)imageName {
    [self.mainQueue addOperationWithBlock:^{
        self.silentLivenessView.hintLabel.text = text;
    }];
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}
@end
